// Copyright 2011 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry5.csrfprotection;

import java.io.IOException;
import org.apache.log4j.Logger;
import org.apache.tapestry5.csrfprotection.services.CsrfProtectedPages;
import org.apache.tapestry5.csrfprotection.services.CsrfProtectionModule;
import org.apache.tapestry5.ioc.annotations.Value;
import org.apache.tapestry5.services.ApplicationStateManager;
import org.apache.tapestry5.services.ComponentEventRequestHandler;
import org.apache.tapestry5.services.ComponentEventRequestParameters;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.Response;

/**
 * This filter checks each component event request or page render request for cross-site request forgery attacks.
 * If a page is marked as protected a request is checked. If the auto mode for the cross-stie request forgery
 * protection is used, all pages are checked except those which are marked as unprotected.
 * @see CsrfProtectionFilter
 */
public class CsrfProtectionFilterImpl implements CsrfProtectionFilter {
	private final ApplicationStateManager applicationStateManager;
	private final Request request;
	private final String antiCsrfMode;	
	private final CsrfProtectedPages csrfProtectedPages;

	private Logger logger = Logger.getLogger(CsrfProtectionFilterImpl.class);

	/**
	 * Creates a new filter and injects the required services and configuration parameters.
	 * @param applicationStateManager
	 * @param request
	 * @param response
	 * @param antiCsrfMode
	 * @param csrfProtectedPages
	 */
	public CsrfProtectionFilterImpl(
			ApplicationStateManager applicationStateManager,
			Request request,
			Response response,			
			@Value("${" + CsrfProtectionModule.ANTI_CSRF_MODE + "}") String antiCsrfMode, 			
			CsrfProtectedPages csrfProtectedPages) {
		super();
		this.applicationStateManager = applicationStateManager;
		this.request = request;
		this.antiCsrfMode = antiCsrfMode;
		this.csrfProtectedPages = csrfProtectedPages;
	}

	/**
	 * Handles a component event request and evaluates the cross-site request forgery protection.
	 * @See CsrfProtectionClassTransformWorker
	 */
	public void handle(ComponentEventRequestParameters parameters,
			ComponentEventRequestHandler handler) throws IOException {
		String pageName = parameters.getContainingPageName();
		
		// if the cross-site request forgery protection is not used return
		if(CsrfProtectionModule.ANTI_CSRF_MODE_OFF.equals(this.antiCsrfMode)){
			handler.handle(parameters);
			return;
		}
		
		if(csrfProtectedPages.isProtected(pageName)){
			logger.debug("CsrfProtectionFilter checks token (Page render).");
			CsrfTokenProvider.checkToken(request, applicationStateManager);
			handler.handle(parameters);
			return;
		}
		if (CsrfProtectionModule.ANTI_CSRF_MODE_AUTO.equals(this.antiCsrfMode)) {
			if(csrfProtectedPages.isUnprotected(pageName)){
				logger.debug("CsrfProtection deactivated for page " + pageName);
			}
			else{
				logger.debug("CsrfProtectionFilter checks token.");
				CsrfTokenProvider.checkToken(request, applicationStateManager);
			}
		}
		handler.handle(parameters);
	}
}
